﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DbView
{
	/*
		Form to display the results of a field lookup. Uses the key attached to a grid column to lookup
		the configuration and forwards this to the driver to create the command to execute.
		Displays the result in a grid which can also contain lookup fields.
	*/
	public partial class LookupResultForm : Form
	{
		private DbViewDriver.IDataSource dataSource; // hold the datasource otherwise no queries will get done
		private string connectionName;				 // key item for finding
		private LookupModel model;					 // for building the report.
		private string searchData;					 // single item or comma-separated list of items to lookup 

		public LookupResultForm(DbViewDriver.IDataSource dataSourceIn, string connectionNameIn, LookupModel modelIn, string searchDataIn)
		{
			InitializeComponent();
			this.searchData = searchDataIn;
			this.dataSource = dataSourceIn;
			this.connectionName = connectionNameIn;
			this.model = modelIn;
			// inherit all the properties of the grid in the main window for a consistebt look
			this.lookupResults.AllowUserToAddRows = false;
			this.lookupResults.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.AllCells;
			this.lookupResults.BackgroundColor = System.Drawing.SystemColors.Desktop;
			this.lookupResults.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.lookupResults.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
			this.lookupResults.GridColor = System.Drawing.SystemColors.ControlLight;
			this.lookupResults.Name = "results";
			this.lookupResults.RowHeadersWidth = 32;
			this.lookupResults.RowTemplate.Height = 18;
			this.lookupResults.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.True;
		}
		
		private void LookupResultForm_Load(object sender, EventArgs e)
		{
			// search to produce the grid data
			this.ExecuteCommand();
		}
		
		private void btnClose_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		//
		// Hacked from the standalone Adhoc query window in main.cs
		//
		private void ExecuteCommand()
		{
			if (searchData.Length == 0)
				return; // do nothing if window is empty
			// 
			try
			{
				// probably never will be null if there is a lookup configuration
				Object o = this.dataSource.TryToGetOptionalInterface(DbViewDriver.OptionalInterface.Lookup);
				if (o != null)
				{
					// the driver must return an object that implements the interface.
					DbViewDriver.ILookup iface = o as DbViewDriver.ILookup;
					// build the command template 
					string sql = iface.BuildLookupCommand(model.LookupTable, model.SelectedFields.ToArray(), model.LookupField, this.searchData); 
					/*
						To deal with the query/command distinction require returned table to be decorated
						with extra info that contains the message
					*/
					// TODO:
					// this.toolStripStatusMessage.Text = "Working...";
				
					Command adhocCommand = new Command(Commands.Cmnd.Adhoc);
					ViewContext vc = new ViewContext(adhocCommand);
					vc.Command = adhocCommand;
					vc.FilterString = sql; // hijack the filter string for the whole script
					// check connection info attached to the source.
					DataTable dt = this.dataSource.BuildTable(adhocCommand, vc);
					DataTableExtraInfoManager mgr = new DbView.DataTableExtraInfoManager(dt);
					this.AttachLookupInfo(dt, this.model.LookupTable, mgr);

					int rows = dt.Rows.Count;

					this.lookupResults.Visible = false; // added for render speed. Remove if it proves ugly
					this.lookupResults.DataSource = null;
					this.lookupResults.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
					this.lookupResults.DefaultCellStyle.WrapMode = DataGridViewTriState.False;

					BindingSource bindSource = new BindingSource();
					// set the BindingSource DataSource
					bindSource.DataSource = dt;
					// set the DataGridView DataSource
					this.lookupResults.DataSource = bindSource;
					// prevent edits unless user asks
					this.lookupResults.ReadOnly = true;
					this.lookupResults.Visible = true; // added for render speed. Remove if it proves ugly
					this.lookupResults.DecorateTable(true, true); // everything please
				
					// TODO
					// this.toolStripStatusMessage.Text = string.Format("Done: {0} rows", rows);
				}
			}
			catch (Exception exc)
			{
				// TODO: Improve this.
				MessageBox.Show(exc.Message);

				// TODO:
				// this.toolStripStatusMessage.Text = "!Error";
			}
		}

		private void AttachLookupInfo(DataTable dataTable, string tableName, DataTableExtraInfoManager infoManager)
		{
			// Only drivers that expose the lookup interface will use this feature
			// (drivers return null to indicate they do no support lookup)
			Object o = this.dataSource.TryToGetOptionalInterface(DbViewDriver.OptionalInterface.Lookup);
			if (o != null)
			{
				// the driver must return an object that implements the interface.
				DbViewDriver.ILookup iface = o as DbViewDriver.ILookup;

				String table = tableName;
				DbView.Resources.LookupInfo.Key partKey = new Resources.LookupInfo.Key(this.dataSource.DriverName, this.connectionName, table, "");
				DbView.Resources.LookupInfo.Key[] tableKeys = DbView.Resources.LookupInfo.Instance.FindKeysForTable(partKey);
				foreach (DbView.Resources.LookupInfo.Key key in tableKeys)
				{
					DbView.Resources.LookupInfo.Data data = DbView.Resources.LookupInfo.Instance.FindData(key);
					if (data != null)
					{
						DataColumn dc = dataTable.Columns[key.Field];
						if (dc != null)
							infoManager.SetLookupKey(dc, key.Table, key.Field);
					}
				}

			}
		}

		private void Results_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			DbViewDataGridView grid = (DbViewDataGridView)sender;
			OnMouseDownInGrid(grid, e.X, e.Y, (e.Button == MouseButtons.Right));
		}

		// From main
		// Lots of fun when you click in a grid.
		private void OnMouseDownInGrid(DbViewDataGridView grid, int gridX, int gridY, bool isRightClick)
		{
			// find out where in the grid the click happened
			DataGridView.HitTestInfo hti = grid.HitTest(gridX, gridY);
			// Click on the left margin of the row
			if (hti.Type == DataGridViewHitTestType.RowHeader)
			{
				// nothing for now.
			}

			// click in a cell 
			if (hti.Type == DataGridViewHitTestType.Cell)
			{
				// decide whether to reset the selection on right-click
				bool resetCurrent = true;  // assume yes
				// if the hit is in the selection then leave the selection intact
				foreach (DataGridViewCell cell in grid.SelectedCells)
				{
					if (cell.ColumnIndex == hti.ColumnIndex && cell.RowIndex == hti.RowIndex)
					{
						resetCurrent = false;
						break;
					}
				}

				if (resetCurrent)
				{
					grid.CurrentCell = grid.Rows[hti.RowIndex].Cells[hti.ColumnIndex];
				}

				if (isRightClick)
				{
					bool wantMenu = this.IsSingleColumnSelected(grid) && this.IsLookupColumn(grid, hti.ColumnIndex);
					if (wantMenu)
					{
						this.ShowLookupContextMenu(grid, gridX, gridY, hti.ColumnIndex);
					}
					else
						// Normal branch: copy to clip and flash
						this.CopyGridCellData(grid, hti.ColumnIndex);
				}
			}
		}

		private void Results_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			DbViewDataGridView myGrid = (DbViewDataGridView)sender;
			System.Windows.Forms.DataGridView.HitTestInfo hti;
			hti = myGrid.HitTest(e.X, e.Y);
			switch (hti.Type)
			{
				case DataGridViewHitTestType.RowHeader:
					InvokeDefaultPopup(); // this performs the default right-click menu option
					return;

				case DataGridViewHitTestType.Cell:
					InvokeDefaultPopup(); // this performs the default right-click menu option
					// .. or if in edit mode pass through to activate cell editing
					return;

				case DataGridViewHitTestType.ColumnHeader:
					// Do nothing or popup view configuration 
					return;
				// anywhere else: nothing
			}
		}

		private void CopyGridCellData(DbViewDataGridView grid, int columnIndex)
		{
			DataRow dr;
			Helper.GetSelectedRow(grid, out dr);
			// account for null datarow return (eg click in the new row)
			//string data = (dr == null) ? "" : dr[hti.ColumnIndex].ToString().Trim();
			//string data = (dr == null) ? "" : dr[columnIndex].ToString().Trim();
			// copy all marked to clipboard, applying the template if any is set
			Clipboard.SetDataObject(grid.GetClipboardContent());
			// below just provides a visual confirmation that the selection is made
			// get the selction background as the cell was selected above
			Color c = grid.DefaultCellStyle.SelectionBackColor;
			// temporarily set the selection colour to red and update screen
			// additional queue: set colour depending on whether a template is active or not.
			grid.DefaultCellStyle.SelectionBackColor = Color.Red;
			grid.Refresh();
			// short delay so colour change is apparent to user
			System.Threading.Thread.Sleep(100);
			// restore
			grid.DefaultCellStyle.SelectionBackColor = c;
			grid.Refresh();
		}

		// from Main: may be useful later?
		private void InvokeDefaultPopup()
		{
		}

		private void ShowLookupContextMenu(DbViewDataGridView grid, int gridX, int gridY, int columnIndex)
		{
			// this needs cutting down
			ContextMenu lookupContextMenu = new ContextMenu();
			MenuItem mi = new MenuItem("Lookup", RightClickLookup_Click);
			mi.Tag = columnIndex;
			lookupContextMenu.MenuItems.Add(mi);

			mi = new MenuItem("Copy", RightClickCopy_Click);
			mi.Tag = columnIndex;
			lookupContextMenu.MenuItems.Add(mi);

			lookupContextMenu.Show(grid, new Point(gridX, gridY));
		}

		private void RightClickCopy_Click(object sender, System.EventArgs e)
		{
			MenuItem mi = sender as MenuItem;
			int columnIndex = System.Convert.ToInt32(mi.Tag);
			CopyGridCellData(this.lookupResults, columnIndex);
		}

		private void RightClickLookup_Click(object sender, System.EventArgs e)
		{
			// Get column index selected from the tag data attached to the menu item
			MenuItem mi = sender as MenuItem;
			int columnIndex = System.Convert.ToInt32(mi.Tag);
			// Get the data. Should really only be here when a single column is selected
			// TODO: make this so.
			Clipboard.SetDataObject(this.lookupResults.GetClipboardContent());
			string clipData = Clipboard.GetText();
			// Multiple cells need converting from a cr list to a comma-list
			// we're being lazy with the type so to be safe enclose the data in quotes
			clipData = "'"+clipData.Replace("\r\n","\n").Replace("\n", "','")+"'";

			LookupModel lu = MakeLookupModel(this.lookupResults, columnIndex);
			LookupResultForm dlg = new LookupResultForm(this.dataSource, this.connectionName, lu, clipData);
			dlg.Show();
		}

		private bool IsLookupColumn(DbViewDataGridView grid, int columnIndex)
		{
		    DataTable dt = grid.GridDataTable;
		    DataTableExtraInfoManager mgr = new DataTableExtraInfoManager(dt);
		    string field = mgr.GetLookupKeyField(dt.Columns[columnIndex]);
		    return string.IsNullOrEmpty(field) ? false : true;
		}

		bool IsSingleColumnSelected(DbViewDataGridView grid)
		{
			DataObject clipData = grid.GetClipboardContent();
			if (!clipData.ContainsText())
				return false;
			string data = clipData.GetText();
			return !data.Contains("\t");
		}

		private LookupModel MakeLookupModel(DbViewDataGridView grid, int columnIndex)
		{
			DataTable dt = grid.GridDataTable;
			DataTableExtraInfoManager mgr = new DataTableExtraInfoManager(dt);
			LookupModel model = new LookupModel();
			model.Table = mgr.GetLookupKeyTable(dt.Columns[columnIndex]);
			model.Field = mgr.GetLookupKeyField(dt.Columns[columnIndex]);
			DbView.Resources.LookupInfo.Key key = new Resources.LookupInfo.Key(this.dataSource.DriverName, this.connectionName, model.Table, model.Field);
			DbView.Resources.LookupInfo.Data data = DbView.Resources.LookupInfo.Instance.FindData(key);
			model = LookupModel.DataTransfer(key, data);
			return model;
		}

		private void btnModify_Click(object sender, EventArgs e)
		{
			object o = this.dataSource.TryToGetOptionalInterface(DbViewDriver.OptionalInterface.Lookup);
			DbViewDriver.ILookup lookupIface = o as DbViewDriver.ILookup;
			LookupEditController controller = new DbView.LookupEditController(lookupIface.GetSchemaInfo(), this.model);
			LookupEditForm dlg = new DbView.LookupEditForm(controller);
			if (dlg.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
			{
				DbView.Resources.LookupInfo.Key key = new Resources.LookupInfo.Key(this.dataSource.DriverName, this.connectionName, this.model.Table, this.model.Field);
			    DbView.Resources.LookupInfo.Data report = LookupModel.DataTransfer(this.model, key);
			    DbView.Resources.LookupInfo.Instance.AddLookup(key, report);
				DbView.Resources.LookupInfo.Instance.SaveConfig();
				this.ExecuteCommand();
			}

		}

		private void btnEnlarge_Click(object sender, EventArgs e)
		{
			// get screen size
			Rectangle scr = this.Bounds;
			int newWidth = (scr.Width * 3)/2;  // 90%
			if (newWidth > 1000) newWidth = 1000;     // hey: not too big
			this.SetBounds(scr.X, scr.Y, newWidth, scr.Height);
		}
		

	}
}
